package com.remedios.mailListener;


import com.alibaba.fastjson2.JSON;
import com.rabbitmq.client.Channel;
import com.remedios.service.MailSendLogService;
import com.ruoyi.common.core.constant.RabbitMqConstants;
import com.ruoyi.system.api.domain.MailSendLog;
import com.ruoyi.system.api.domain.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;


import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @
 */
@Component
@Slf4j
public class MailListener {
    @Autowired
    JavaMailSender javaMailSender;
    @Autowired
    MailProperties mailProperties;
    @Autowired
    TemplateEngine templateEngine;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    MailSendLogService mailSendLogService;


    @RabbitListener(queues = RabbitMqConstants.EMAIL_QUEUE)
    public void sendMail(String userJSON, Message message)  {
        String correlationDataId = (String) message.getMessageProperties().getHeaders().get(RabbitMqConstants.MESSAGE_CORRELATION);
        String messageKey = RabbitMqConstants.CORRELATION_ID + correlationDataId;
        //消息幂等处理
        if (!redisTemplate.hasKey(messageKey)) {
            return;
        }

        SysUser user = getSysUser(userJSON);
        mailSendLogService.sendMessage(correlationDataId, messageKey, user);

    }

    @RabbitListener(queues = RabbitMqConstants.FAILED_QUEUE)
    public void failedMail(Message message)  {
        String correlationDataId = (String) message.getMessageProperties().getHeaders().get(RabbitMqConstants.MESSAGE_CORRELATION);
        String messageKey = RabbitMqConstants.CORRELATION_ID + correlationDataId;
        //幂等处理
        if (!redisTemplate.hasKey(messageKey)) {
            return;
        }
        SysUser user = getSysUser(messageKey);
        MailSendLog mailSendLog = new MailSendLog();
        mailSendLog.setMsgId(correlationDataId);
        mailSendLog.setStatus(RabbitMqConstants.FAILURE);
        mailSendLog.setUpdateTime(new Date());
        mailSendLog.setPassword((String) user.getParams().get("unencrypted"));
        mailSendLogService.updateMailSendLog(mailSendLog);
        redisTemplate.delete(messageKey);
    }

    private SysUser getSysUser(String userJSON) {
        Object parse = JSON.parse(userJSON);
        SysUser user = JSON.parseObject((String) parse, SysUser.class);
        return user;
    }


    public void  sendMessage(String correlationDataId, String messageKey, SysUser user) {
        MimeMessage msg = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(msg);

        try {
            helper.setTo(user.getEmail());
            helper.setFrom(mailProperties.getUsername());
            helper.setSubject("入职欢迎");
            helper.setSentDate(new Date());
            Context context = new Context();
            context.setVariable("nickName", user.getNickName());
            context.setVariable("name", user.getUserName());
            context.setVariable("password", user.getParams().get("unencrypted"));
            context.setVariable("date", LocalDate.now());
            String mail = templateEngine.process("mail", context);
            helper.setText(mail, true);
            //发送邮件
            javaMailSender.send(msg);
            //模拟消息消费完成
            log.info("++++++ 消息消费成功:{}", correlationDataId);

            log.info("++++++ 清除message缓存:{}", correlationDataId);
            //清除message缓存
            redisTemplate.delete(messageKey);
            MailSendLog mailSendLog = new MailSendLog();
            mailSendLog.setMsgId(correlationDataId);
            mailSendLog.setStatus(RabbitMqConstants.SUCCESS);
            mailSendLogService.updateMailSendLog(mailSendLog);
        } catch (MessagingException e) {
            throw new RuntimeException("邮件发送出现异常");
        }
    }

}



//    @RabbitListener(queues = "emailQueue")
//    public void sendMail(String userJSON, Message message, Channel channel) throws IOException {
//
//        String correlationDataId = (String) message.getMessageProperties().getHeaders().get("CORRELATION_DATA_ID:");
//        //message缓存的key值
//        String messageKey = "CORRELATION_DATA_ID:" + correlationDataId;
//        //消息消费
//        try {
//            //消息幂等处理
//            if (!redisTemplate.hasKey(messageKey)) {
//                return;
//            }
//            //获取消息内容
////            Map<String, String> map = (Map) SerializationUtils.deserialize(message.getBody());
//            SysUser user = JSON.parseObject(userJSON, SysUser.class);
//            MimeMessage msg = javaMailSender.createMimeMessage();
//            MimeMessageHelper helper = new MimeMessageHelper(msg);
////        try {
//            helper.setTo(user.getEmail());
//            helper.setFrom(mailProperties.getUsername());
//            helper.setSubject("入职欢迎");
//            helper.setSentDate(new Date());
//            Context context = new Context();
//            context.setVariable("name", user.getUserName());
//            context.setVariable("password", user.getParams().get("unencrypted"));
//            String mail = templateEngine.process("mail", context);
//            helper.setText(mail, true);
//            //发送邮件
////            javaMailSender.send(msg);
//            //模拟消息消费完成
//            log.info("++++++ 消息消费成功:{}", correlationDataId);
//
//            log.info("++++++ 清除message缓存:{}", correlationDataId);
//            //清除message缓存
//            redisTemplate.delete(messageKey);
//            int a = 1 / 0;
//            MailSendLog mailSendLog = new MailSendLog();
//            mailSendLog.setMsgId(correlationDataId);
//            mailSendLog.setStatus(1);
//            mailSendLogService.update(mailSendLog);
//            log.info("++++++ 更新failed_message中消息消费失败记录:{}", correlationDataId);
//        } catch (Exception e) {
//            if(!redisTemplate.hasKey(messageKey)){
//                log.info("这个异常是发送完邮件出现的 消费成功了 找找其他原因");
//                return;
//            }
//                //获取重试次数
//            long retryCount = getRetryCount(message.getMessageProperties());
//            Message newMessage = message;
//
//            if (retryCount >= 3) {
//
//                //重试超过3次的，直接存入失败队列
//                /** 如果重试次数大于3,则将消息发送到失败队列等待人工处理 */
//                try {
//                    //清除message缓存
//                    redisTemplate.delete(messageKey);
//
//                    log.info("++++++ 重试超过3次，直接存入失败队列:{}次，重发消息{}",retryCount+1,correlationDataId);
//                    rabbitTemplate.convertAndSend("failedExchange",
//                            "email.failed.resume", newMessage);
//                    log.info("用户体系服务消费者消费消息在重试3次后依然失败，将消息发送到fail队列,发送消息:" + new String(newMessage.getBody()));
//                } catch (Exception e1) {
//                    log.error("用户体系服务消息在发送到fail队列的时候报错:" + e1.getMessage() + ",原始消息:"
//                            + new String(newMessage.getBody()));
//                }
//            } else {
//                try {
//                    log.info("++++++ 消息消费重试:{}次，{}",retryCount+1,correlationDataId);
//                    log.info("++++++ 消息消费重试:{}次，更新缓存{}",retryCount+1,correlationDataId);
//                    //更新缓存
//                    redisTemplate.opsForValue().set(messageKey,JSON.toJSONString(newMessage));
//                    log.info("++++++ 消息消费重试:{}次，重发消息{}",retryCount+1,correlationDataId);
//                    /** 如果当前消息被重试的次数小于3,则将消息发送到重试队列,等待重新被消费{延迟消费} */
//                    rabbitTemplate.convertAndSend("retryExchange",
//                            "email.retry.myRetry", newMessage,new CorrelationData(correlationDataId));
//                    log.info("用户服务消费者消费失败，消息发送到重试队列;" + "原始消息：" + new String(newMessage.getBody()) + ";第"
//                            + (retryCount+1) + "次重试");
//                } catch (Exception e1) {
//                    // 如果消息在重发的时候,出现了问题,可用nack,经过开发中的实际测试，当消息回滚到消息队列时，
//                    // 这条消息不会回到队列尾部，而是仍是在队列头部，这时消费者会立马又接收到这条消息，进行处理，接着抛出异常，
//                    // 进行回滚，如此反复进行。这种情况会导致消息队列处理出现阻塞，消息堆积，导致正常消息也无法运行
//                    // channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
//                    // 改为重新发送消息,经过多次重试后，如果重试次数大于3,就不会再走这，直接丢到了fail queue等待人工处理
//                    log.error("消息发送到重试队列的时候，异常了:" + e1.getMessage() + ",重新发送消息");
//                }
//            }
//        } finally {
//            /**
//             * 关闭rabbitmq的自动ack,改为手动ack 1、因为自动ack的话，其实不管是否成功消费了，rmq都会在收到消息后立即返给生产者ack,但是很有可能 这条消息我并没有成功消费
//             * 2、无论消费成功还是消费失败,都要手动进行ack,因为即使消费失败了,也已经将消息重新投递到重试队列或者失败队列
//             * 如果不进行ack,生产者在超时后会进行消息重发,如果消费者依然不能处理，则会存在死循环
//             */
//            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
//        }
//    }